package com.study4j.crontab.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.study4j.common.exception.ServerException;
import com.study4j.crontab.model.BaseTask;
import com.study4j.crontab.model.CrontabVO;
import com.study4j.crontab.service.IQuartzJobManagerService;

import lombok.extern.slf4j.Slf4j;

/**
 * @description 定时任务管理service实现类
 * @author Jiangbin
 * @date 2019年7月25日 下午3:11:11
 * @version 1.0.0
 */
@Service
@Slf4j
public class QuartzJobManagerServiceImpl implements IQuartzJobManagerService {

	@Autowired
	private Scheduler scheduler;

	@Override
	public void addJob(Job job, String jobName, String jobGroupName, String cronExpression) {
		addJob(job, jobName, jobGroupName, cronExpression, null);
	}

	@Override
	public void addJob(CrontabVO crontabVO){
		try {
			// 启动调度器
			scheduler.start();
			BaseTask baseTask = ((BaseTask) Class.forName(crontabVO.getTaskClassName()).getDeclaredConstructor()
					.newInstance());
			// 构建job信息
			JobDetail jobDetail = JobBuilder.newJob(baseTask.getClass())
					.withIdentity(crontabVO.getTaskClassName(), crontabVO.getTaskGroupName()).build();
			// 表达式调度构建器(即任务执行的时间)
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(crontabVO.getCronExpression());
			// 按新的cronExpression表达式构建一个新的trigger
			CronTrigger trigger = TriggerBuilder.newTrigger()
					.withIdentity(crontabVO.getTaskClassName(), crontabVO.getTaskGroupName())
					.withSchedule(scheduleBuilder).build();
			// 获得JobDataMap，写入数据
			Map<String, Object> argMap = crontabVO.getArgMap();
			if (argMap != null) {
				trigger.getJobDataMap().putAll(argMap);
			}
			scheduler.scheduleJob(jobDetail, trigger);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("定时任务添加失败！");
			throw new ServerException("定时任务添加失败！");
		}
	}

	@Override
	public void addJob(Job job, String jobName, String jobGroupName, String cronExpression,
			Map<String, Object> argMap) {
		try {
			// 启动调度器
			scheduler.start();
			// 构建job信息
			JobDetail jobDetail = JobBuilder.newJob(job.getClass()).withIdentity(jobName, jobGroupName).build();
			// 表达式调度构建器(即任务执行的时间)
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
			// 按新的cronExpression表达式构建一个新的trigger
			CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
					.withSchedule(scheduleBuilder).build();
			// 获得JobDataMap，写入数据
			if (argMap != null) {
				trigger.getJobDataMap().putAll(argMap);
			}
			scheduler.scheduleJob(jobDetail, trigger);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("定时任务添加失败！");
			throw new ServerException("定时任务添加失败！");
		}
	}

	@Override
	public void pauseJob(String jobName, String jobGroupName) {
		try {
			scheduler.pauseJob(JobKey.jobKey(jobName, jobGroupName));
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void resumeJob(String jobName, String jobGroupName) {
		try {
			scheduler.resumeJob(JobKey.jobKey(jobName, jobGroupName));
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}

	public void updateJob(String jobName, String jobGroupName, String cronExpression) {
		updateJob(jobName, jobGroupName, cronExpression, null);

	}

	@Override
	public void updateJob(String jobName, String jobGroupName, String cronExpression, Map<String, Object> argMap) {
		try {
			TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
			// 表达式调度构建器
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			// 按新的cronExpression表达式重新构建trigger
			trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
			// 修改map
			if (argMap != null) {
				trigger.getJobDataMap().putAll(argMap);
			}
			// 按新的trigger重新设置job执行
			scheduler.rescheduleJob(triggerKey, trigger);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("定时任务更新失败！");
			throw new ServerException("定时任务更新失败！");
		}
	}
	
	@Override
	public void updateJob(CrontabVO crontabVO) {
		try {
			TriggerKey triggerKey = TriggerKey.triggerKey(crontabVO.getTaskClassName(), crontabVO.getTaskGroupName());
			// 表达式调度构建器
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(crontabVO.getCronExpression());
			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			// 按新的cronExpression表达式重新构建trigger
			trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
			// 修改map
			Map<String, Object> argMap = crontabVO.getArgMap();
			if (argMap != null) {
				trigger.getJobDataMap().putAll(argMap);
			}
			// 按新的trigger重新设置job执行
			scheduler.rescheduleJob(triggerKey, trigger);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("定时任务更新失败！");
			throw new ServerException("定时任务更新失败！");
		}
	}

	@Override
	public void updateJob(String jobName, String jobGroupName, Map<String, Object> argMap) {
		try {
			TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			// 修改map
			trigger.getJobDataMap().putAll(argMap);
			// 按新的trigger重新设置job执行
			scheduler.rescheduleJob(triggerKey, trigger);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("定时任务更新失败！");
			throw new ServerException("定时任务更新失败！");
		}

	}

	@Override
	public void deleteJob(String jobName, String jobGroupName) {
		try {
			scheduler.pauseTrigger(TriggerKey.triggerKey(jobName, jobGroupName));
			scheduler.unscheduleJob(TriggerKey.triggerKey(jobName, jobGroupName));
			scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
		} catch (Exception e) {
			e.printStackTrace();
			log.error("定时任务删除失败！");
			throw new ServerException("定时任务删除失败！");
		}
	}

	@Override
	public void startAllJobs() {
		try {
			scheduler.start();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public void shutdownAllJobs() {
		try {
			if (!scheduler.isShutdown()) {
				scheduler.shutdown();
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public List<Map<String, Object>> getAllJob() {
		GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
		List<Map<String, Object>> jobList = new ArrayList<>();
		Set<JobKey> jobKeys = null;
		try {
			jobKeys = scheduler.getJobKeys(matcher);
			for (JobKey jobKey : jobKeys) {
				List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
				for (Trigger trigger : triggers) {
					Map<String, Object> job = new HashMap<>();
					job.put("jobName", jobKey.getName());
					job.put("jobGroupName", jobKey.getGroup());
					job.put("trigger", trigger.getKey());
					Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
					job.put("jobStatus", triggerState.name());
					if (trigger instanceof CronTrigger) {
						CronTrigger cronTrigger = (CronTrigger) trigger;
						String cronExpression = cronTrigger.getCronExpression();
						job.put("cronExpression", cronExpression);
					}
					jobList.add(job);
				}
			}
		} catch (SchedulerException e) {
			e.printStackTrace();
			log.error("定时任务列表获取异常！");
			throw new ServerException("定时任务列表获取异常！");
		}

		return jobList;
	}

}
